/*
 * Copyright (C) 2004-2007  Autodesk, Inc.
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of version 2.1 of the GNU Lesser
 * General Public License as published by the Free Software Foundation.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

#include "Pch.h"
#include "OverridesTest.h"
#include "UnitTestUtil.h"
#include "XmlFormatter.h"
#include "FdoCommonFile.h"
#include "WCS/Override/FdoWcsOvPhysicalSchemaMapping.h"
#include "FdoCommonOSUtil.h"

#include <time.h>

CPPUNIT_TEST_SUITE_REGISTRATION( OverridesTest );
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( OverridesTest, "OverridesTest");

OverridesTest::OverridesTest(void)
{
    schemaNames = FdoStringCollection::Create();
    classNames = FdoStringCollection::Create();
    rasterPropertyNames = FdoStringCollection::Create();
    coverageNames = FdoStringCollection::Create();
    identifiers = FdoStringCollection::Create();
    formatNames = FdoStringCollection::Create();
    bBoxMinX = FdoStringCollection::Create();
    bBoxMinY = FdoStringCollection::Create();
    bBoxMaxX = FdoStringCollection::Create();
    bBoxMaxY = FdoStringCollection::Create();


    schemaNames->Add(L"Schema1");
    schemaNames->Add(L"Schema2");

    classNames->Add(L"Class1");
    classNames->Add(L"Class2");

    rasterPropertyNames->Add(L"Raster1");
    rasterPropertyNames->Add(L"Raster2");

    coverageNames->Add(L"Coverage1");
    coverageNames->Add(L"Coverage2");

    identifiers->Add(L"Identifier1");
    identifiers->Add(L"Identifier2");

    formatNames->Add(L"image/GeoTIFF");
    formatNames->Add(L"image/NITF");

    bBoxMinX->Add(L"-179.999998745864");
    bBoxMinX->Add(L"-3961770.085");

    bBoxMinY->Add(L"34.9037152643753");
    bBoxMinY->Add(L"-3961769.906");

    bBoxMaxX->Add(L"178.959571606408");
    bBoxMaxX->Add(L"3961769.894");

    bBoxMaxY->Add(L"53.7717181062498");
    bBoxMaxY->Add(L"4362961.971");
}

OverridesTest::~OverridesTest(void)
{
}

void OverridesTest::TestCreateSchemaOverrides()
{
    try {
        FdoInt32 iSchemaCnt = schemaNames->GetCount();
        for (FdoInt32 i=0; i < iSchemaCnt; i++)
        {
            FdoWcsOvPhysicalSchemaMappingP config = FdoWcsOvPhysicalSchemaMapping::Create();
            config->SetName(schemaNames->GetString(i));

            FdoWcsOvClassesP classes = config->GetClasses();
            FdoInt32 iClassCnt = classNames->GetCount();
            for (FdoInt32 j=0; j < iClassCnt; j++)
            {
                FdoWcsOvClassDefinitionP classDefn = FdoWcsOvClassDefinition::Create();
                FdoStringP str;
                classDefn->SetName(str = classNames->GetString(j));

                FdoWcsOvRasterDefinitionP rasterDefn = FdoWcsOvRasterDefinition::Create();
                str = rasterPropertyNames->GetString(j);
                rasterDefn->SetName(str);
                rasterDefn->SetSpatialContextName(L"EPSG:4326");

                FdoWcsOvCoveragesP coverages = rasterDefn->GetCoverages();
                FdoInt32 iCoverageCnt = coverageNames->GetCount();
                for (FdoInt32 k=0; k < iCoverageCnt; k++)
                {
                    FdoWcsOvCoverageDefinitionP coverDefn = FdoWcsOvCoverageDefinition::Create();
                    coverDefn->SetName(str = coverageNames->GetString(k));

                    coverDefn->SetIdentifier(str = identifiers->GetString(k));
                    coverDefn->SetImageFormat(str = formatNames->GetString(k));

                    FdoWcsOvBoundingBoxDefinitionP bBox = FdoWcsOvBoundingBoxDefinition::Create();
                    bBox->SetMinX(FdoCommonOSUtil::wtof(bBoxMinX->GetString(k)));
                    bBox->SetMinY(FdoCommonOSUtil::wtof(bBoxMinY->GetString(k)));
                    bBox->SetMaxX(FdoCommonOSUtil::wtof(bBoxMaxX->GetString(k)));
                    bBox->SetMaxY(FdoCommonOSUtil::wtof(bBoxMaxY->GetString(k)));
                    coverDefn->SetBoundingBox(bBox);

                    coverages->Add(coverDefn);
                }

                classDefn->SetRasterDefinition(rasterDefn);
                classes->Add(classDefn);
            }

            TestNewConfiguration(config, i);
        }
    }
    catch (FdoException* e) 
    {
        fail (e);
    }
}

void OverridesTest::TestNewConfiguration(FdoWcsOvPhysicalSchemaMapping* schemaMapping, FdoInt32 schemaIndex)
{
    try {
        FdoStringP name = schemaMapping->GetName();
        if (name != schemaNames->GetString(schemaIndex)) {
            CPPUNIT_FAIL("FAILED - FdoWcsOvPhysicalSchemaMapping::GetName()");
        }

        FdoWcsOvClassesP classes = schemaMapping->GetClasses();
        FdoInt32 iClassCnt = classNames->GetCount();
        for (FdoInt32 j=0; j < iClassCnt; j++)
        {
            FdoWcsOvClassDefinitionP classDefn = classes->GetItem(j);
            FdoStringP name = classDefn->GetName();
            if (name != classNames->GetString(j)) {
                CPPUNIT_FAIL("FAILED - FdoWcsOvClassDefinition::GetName()");
            }

            FdoWcsOvRasterDefinitionP rasterDefinition = classDefn->GetRasterDefinition();
            FdoStringP rasterPropName = rasterDefinition->GetName();
            if (rasterPropName != rasterPropertyNames->GetString(j)) {
                CPPUNIT_FAIL("FAILED - FdoWcsOvRasterDefinition::GetName()");
            }

            FdoStringP sc = rasterDefinition->GetSpatialContextName();
            if (sc != L"EPSG:4326") {
                CPPUNIT_FAIL("FAILED - FdoWcsOvRasterDefinition::GetImageFormat()");
            }

            FdoWcsOvCoveragesP coverages = rasterDefinition->GetCoverages();
            FdoInt32 iCoverageCnt = coverages->GetCount();
            for (FdoInt32 k=0; k < iCoverageCnt; k++)
            {
                FdoWcsOvCoverageDefinitionP coverDefn = coverages->GetItem(k);
                FdoStringP name = coverDefn->GetName();
                if (name != coverageNames->GetString(k)) {
                    CPPUNIT_FAIL("FAILED - FdoWcsOvCoverageDefinition::GetName()");
                }

                FdoStringP id = coverDefn->GetIdentifier();
                if (id != identifiers->GetString(k)) {
                    CPPUNIT_FAIL("FAILED - FdoWcsOvCoverageDefinition::GetIdentifier()");
                }
                FdoStringP format = coverDefn->GetImageFormat();
                if (format != formatNames->GetString(k)) {
                    CPPUNIT_FAIL("FAILED - FdoWcsOvFormatDefinition::GetImageFormat()");
                }

                FdoWcsOvBoundingBoxDefinitionP bBox = coverDefn->GetBoundingBox();
                FdoDouble dVal = bBox->GetMinX();
                if (dVal != FdoCommonOSUtil::wtof(bBoxMinX->GetString(k))) {
                    CPPUNIT_FAIL("FAILED - FdoWcsOvBoundingBoxDefinition::GetMinX()");
                }
                dVal = bBox->GetMinY();
                if (dVal != FdoCommonOSUtil::wtof(bBoxMinY->GetString(k))) {
                    CPPUNIT_FAIL("FAILED - FdoWcsOvBoundingBoxDefinition::GetMinY()");
                }
                dVal = bBox->GetMaxX();
                if (dVal != FdoCommonOSUtil::wtof(bBoxMaxX->GetString(k))) {
                    CPPUNIT_FAIL("FAILED - FdoWcsOvBoundingBoxDefinition::GetMaxX()");
                }
                dVal = bBox->GetMaxY();
                if (dVal != FdoCommonOSUtil::wtof(bBoxMaxY->GetString(k))) {
                    CPPUNIT_FAIL("FAILED - FdoWcsOvBoundingBoxDefinition::GetMaxY()");
                }
            }
        }
    }
    catch (FdoException* e) 
    {
        fail (e);
    }
}

// TestSimple() reads in a simple Schema override into a memory stream and 
// writes that stream directly back to file. During this process it removes all 
// of the line feed and tab characters ensuring the file is contained on a single 
// line for easy comparison. This file becomes the GOLD data for the test. Secondly, 
// this test uses the Overrides API to write the file to a second stream and 
// then writes the stream to disk, once again removing the new line and tab chars. 
// This test finally compared the two documents to see if they are identical.
void OverridesTest::TestSimple () 
{
    try {
        srand((unsigned)time(NULL));

        FdoSchemaMappingsP mappings = FdoPhysicalSchemaMappingCollection::Create();
        FdoXmlReaderP configReader = FdoXmlReader::Create(L"WcsOverridesConfig.xml");
        mappings->ReadXml(configReader);

        FdoWcsOvPhysicalSchemaMappingP config = static_cast<FdoWcsOvPhysicalSchemaMapping*>(mappings->GetItem(0));

        TestConfiguration(config);

        FdoIoStreamP baseConfigStream = configReader->GetStream();
        FdoStringP baseConfigFileName = FdoStringP::Format(L"WcsOverridesConfig_w%3d.xml", rand());
        Stream2File(baseConfigStream, baseConfigFileName);

        FdoIoMemoryStreamP configStream = FdoIoMemoryStream::Create();
        config->WriteXml(configStream);
        FdoStringP configFileName = FdoStringP::Format(L"WcsOverridesConfig_w%3d.xml", rand());
        Stream2File(configStream, configFileName);

#ifdef _WIN32
        // Note: the space in xml(WcsOverridesConfig.xml etc.) should not contain space, 
        // They can be replaced with tab.
        // because, WriteXml method may ignore space, but CheckOutput method will check it.
        UnitTestUtil::CheckOutput(baseConfigFileName, configFileName);
#endif
    }
    catch (FdoException* e) 
    {
        fail (e);
    }
    catch (char* error) 
    {
        fail (error);
    }
}

void OverridesTest::Stream2File( FdoIoStream* stream, FdoString* fileName )
{
    stream->Reset();
    FdoIoFileStreamP fileStream = FdoIoFileStream::Create( fileName, L"w+t" );
    XmlFormatter formatter(stream, fileStream);
    formatter.Format();
}

void OverridesTest::TestConfiguration(FdoWcsOvPhysicalSchemaMapping* schemaMapping)
{
    // TODO: to be implemented
    try {
        TestBaseProperties(schemaMapping);
        FdoString * providerName = schemaMapping->GetProvider();

        FdoWcsOvClassesP classes = schemaMapping->GetClasses();
        FdoInt32 iClassCnt = classes->GetCount();
        for (FdoInt32 i=0; i < iClassCnt; i++) {
            FdoWcsOvClassDefinitionP classDefn = classes->GetItem(i);
            TestBaseProperties(classDefn);

            FdoWcsOvRasterDefinitionP rasterDefn = classDefn->GetRasterDefinition();
            TestBaseProperties(rasterDefn);

            FdoStringP sc = rasterDefn->GetSpatialContextName();

            FdoWcsOvCoveragesP coverages = rasterDefn->GetCoverages();
            FdoInt32 iCoverageCnt = coverages->GetCount();
            for (FdoInt32 j=0; j < iCoverageCnt; j++) {
                FdoWcsOvCoverageDefinitionP coverDefn = coverages->GetItem(j);
                TestBaseProperties(coverDefn);

                FdoStringP str = coverDefn->GetIdentifier();
                str = coverDefn->GetImageFormat();

                FdoWcsOvBoundingBoxDefinitionP bBox = coverDefn->GetBoundingBox();
                TestBaseProperties(bBox);
            }
        }
    }
    catch (FdoException* e) 
    {
        fail (e);
    }
    catch (char* error) 
    {
        fail (error);
    }
}

void OverridesTest::TestBaseProperties(FdoPhysicalElementMapping* elementMapping)
{
    try {
        FdoString * name = elementMapping->GetName();
        FdoStringP qualifiedName = elementMapping->GetQualifiedName();
        FdoPtr<FdoPhysicalElementMapping> parentMapping = elementMapping->GetParent();
        FdoPtr<FdoPhysicalSchemaMapping> schemaMapping = elementMapping->GetSchemaMapping();
    }
    catch (FdoException* e) 
    {
        fail (e);
    }
    catch (char* error) 
    {
        fail (error);
    }
}

void OverridesTest::TestSetConfiguration()
{
    try
    {
        FdoPtr<FdoIConnection> connection = WcsTests::GetConnection();
        if (connection == NULL) {
            CPPUNIT_FAIL("FAILED - CreateConnection returned NULL\n");
        }

        connection->SetConnectionString(L"FeatureServer=http://nsidc.org/cgi-bin/atlas_north");
        FdoIoFileStreamP fileStream = FdoIoFileStream::Create(L"WcsSchemaConfig.xml", L"r");

        connection->SetConfiguration(fileStream);
        connection->Open();
        connection->Close();

        connection->SetConfiguration(fileStream);
        connection->SetConfiguration(fileStream);

        connection->Open();

        bool bFail = false;
        try
        {
            connection->SetConfiguration(fileStream);
        }
        catch (FdoException *e)
        {
            bFail = true;
            e->Release();
        }

        if (bFail == false) {
            CPPUNIT_FAIL("FAILED - SetConfiguration() while state == Open should not be supported\n");
        }

        connection->Close();
    }
    catch (FdoException* e) 
    {
        fail (e);
    }
}

//// Test configuration, which contains the new xml image format, like "image/tiff; PhotometricInterpretation=RGB"
//void OverridesTest::TestRequestSpcialImageFormat()
//{
//    try
//    {   
//        FdoPtr<FdoIConnection> connection = WcsTests::GetConnection();
//        if (connection == NULL) {
//            CPPUNIT_FAIL("FAILED - CreateConnection returned NULL\n");
//        }
//
//        connection->SetConnectionString(L"FeatureServer=http://demo.cubewerx.com/demo/cubeserv/cubeserv.cgi?version=1.1.0"); 
//        FdoIoFileStreamP fileStream = FdoIoFileStream::Create(L"newconfig1.xml", L"r"); // config for WMS 3.3
//
//        connection->SetConfiguration(fileStream);
//        connection->Open();
//
//        FdoPtr<FdoISelect> cmdSelect = static_cast<FdoISelect*> (connection->CreateCommand (FdoCommandType_Select));
//        cmdSelect->SetFeatureClassName (L"WMSLayers:BARRIERL_1M Foundation");
//        FdoPtr<FdoIFeatureReader> featReader = cmdSelect->Execute ();
//        CPPUNIT_ASSERT (featReader->ReadNext ());        
//        FdoPtr<FdoIRaster> raster = featReader->GetRaster (L"Image");
//        FdoPtr<FdoIStreamReaderTmpl<FdoByte> > byteStreamReader = static_cast<FdoIStreamReaderTmpl<FdoByte>*> (raster->GetStreamReader ());
//
//        FdoByte buff[4096];
//        FdoInt64 cntTotal = 0;
//        FdoInt32 cntRead = 0;
//        do
//        {
//            cntRead = byteStreamReader->ReadNext (buff, 0 , 4096);
//            cntTotal += cntRead;
//        }
//        while (cntRead);
//
//        CPPUNIT_ASSERT (cntTotal > 0);
//        CPPUNIT_ASSERT (!featReader->ReadNext ());
//
//        connection->Close();
//        
//    }
//    catch (FdoException* e) 
//    {
//        fail (e);
//    }
//}
//
//// Test configuration, which contains the new xml image format, like "image/tiff; PhotometricInterpretation=RGB"
//void OverridesTest::TestRequestUnsupportedImage()
//{
//    try
//    {   
//        FdoPtr<FdoIConnection> connection = WcsTests::GetConnection();
//        if (connection == NULL) {
//            CPPUNIT_FAIL("FAILED - CreateConnection returned NULL\n");
//        }
//
//        connection->SetConnectionString(L"FeatureServer=http://www2.dmsolutions.ca/cgi-bin/mswms_gmap?version=1.3.0"); 
//        FdoIoFileStreamP fileStream = FdoIoFileStream::Create(L"newconfig.xml", L"r"); // WMS 3.3
//        connection->SetConfiguration(fileStream);
//        connection->Open();
//      
//        FdoPtr<FdoISelect> cmdSelect = static_cast<FdoISelect*> (connection->CreateCommand (FdoCommandType_Select));
//        cmdSelect->SetFeatureClassName (L"WMSLayers:rail"); 
//        FdoPtr<FdoIFeatureReader> featReader = cmdSelect->Execute ();
//        CPPUNIT_ASSERT (featReader->ReadNext ());        
//        FdoPtr<FdoIRaster> raster = featReader->GetRaster (L"Image");
//        FdoPtr<FdoIStreamReaderTmpl<FdoByte> > byteStreamReader = static_cast<FdoIStreamReaderTmpl<FdoByte>*> (raster->GetStreamReader ());
//
//        FdoByte buff[4096];
//        FdoInt64 cntTotal = 0;
//        FdoInt32 cntRead = 0;
//        do
//        {
//            cntRead = byteStreamReader->ReadNext (buff, 0 , 4096);
//            cntTotal += cntRead;
//        }
//        while (cntRead);
//
//        CPPUNIT_ASSERT (cntTotal > 0);
//        CPPUNIT_ASSERT (!featReader->ReadNext ());
//
//        connection->Close();
//
//        fail("<Unsupported Image Format> Exception is not thrown out.");
//    }
//    catch (FdoException* e) 
//    {
//        e->Release();
//    }
//
//}

void OverridesTest::TestQualifiedName()
{
    try
    {
        FdoPtr<FdoIConnection> conn = this->GetConnection ();
        FdoIoFileStreamP fileStream = FdoIoFileStream::Create(L"Atlas_North_WCS_Config.xml", L"r");
        conn->SetConnectionString (L"FeatureServer=http://nsidc.org/cgi-bin/atlas_north");
        conn->SetConfiguration (fileStream);
        CPPUNIT_ASSERT (FdoConnectionState_Open == conn->Open ());

        FdoPtr<FdoIDescribeSchemaMapping> cmd = static_cast<FdoIDescribeSchemaMapping *>(conn->CreateCommand(FdoCommandType_DescribeSchemaMapping));
        FdoPtr<FdoPhysicalSchemaMappingCollection> mappings = cmd->Execute ();
        int cntSchema = mappings->GetCount ();
        for (int i=0; i<cntSchema; i++)
        {
            FdoPtr<FdoPhysicalSchemaMapping> mapping = mappings->GetItem (i);
            FdoWcsOvPhysicalSchemaMapping* schemaMapping = dynamic_cast<FdoWcsOvPhysicalSchemaMapping *>(mapping.p);
            FdoStringP schemaQName = schemaMapping->GetQualifiedName ();
            CPPUNIT_ASSERT (wcscmp (L"Atlas_North", (FdoString*)schemaQName) == 0 );
#ifdef _DEBUG
            wprintf (L"Schema: %ls\n", (FdoString*)schemaQName);
#endif
            FdoPtr<FdoPhysicalElementMapping> parent = schemaMapping->GetParent ();
            if (parent)
            {
                FdoStringP qName = parent->GetQualifiedName ();
            }

            FdoPtr<FdoWcsOvClassCollection> classMappings = schemaMapping->GetClasses ();
            int cntClass = classMappings->GetCount ();
            for (int j=0; j<cntClass; j++)
            {
                FdoPtr<FdoWcsOvClassDefinition> classMapping = classMappings->GetItem (j);
                FdoStringP classQName = classMapping->GetQualifiedName ();
                CPPUNIT_ASSERT (wcscmp (L"Atlas_North:Coverage", (FdoString*)classQName) == 0);
#ifdef _DEBUG
                wprintf (L"Class: %ls\n", (FdoString*)classQName);
#endif
                FdoPtr<FdoWcsOvRasterDefinition> rasterDef = classMapping->GetRasterDefinition ();
                FdoStringP rasterDefQName = rasterDef->GetQualifiedName ();
                CPPUNIT_ASSERT (wcscmp (L"Atlas_North:Coverage.Image", (FdoString*)rasterDefQName) == 0);
#ifdef _DEBUG
                wprintf (L"Property: %ls\n", (FdoString*)rasterDefQName);
#endif
            }
        }
    }
    catch(FdoException* ex)
    {
        fail(ex);
    }
}
